#include "TetrisPiece.h"
#include "OgreSceneManager.h"

using namespace Ogre;

int cTetrisPiece::m_nPieceId = 0;

cTetrisPiece::cTetrisPiece(SceneManager* pScene, eTetrisPiece type, float fRot)
:	m_pParentNode(NULL)
,	m_vParentPos(Vector3::ZERO)
,	m_vInitialPos(Vector3::ZERO)
{
	sprintf(m_szPieceId, "TetrisPiece_%d", m_nPieceId++);
	MakePiece(pScene, type, fRot);
}

cTetrisPiece::~cTetrisPiece()
{
}

void cTetrisPiece::Update(float fDeltaTime, const Ogre::Vector3& vDir, float speed, const Ogre::Vector3& vOffset)
{
	m_vParentPos += vDir * fDeltaTime * speed; 
	m_vParentPos += vOffset;
	if (m_pParentNode)
		m_pParentNode->setPosition(m_vParentPos);
}

void cTetrisPiece::MakePiece(Ogre::SceneManager* pScene, eTetrisPiece type, float fRot)
{
	if (!pScene)
		return;
	Entity*		pEntCube    = NULL;	
	SceneNode*	pNodeCube   = NULL;
	m_pParentNode = pScene->getRootSceneNode()->createChildSceneNode(m_szPieceId);

	int		nCubeIdx = 0;
	char	szId[64];
	Vector3 vCubePos	 = Vector3::ZERO;
	Vector3 vScaleFactor = Vector3::ZERO;
	AxisAlignedBox	aabb;

	switch (type)
	{
		case PIECE_I:
		{
			m_vParentPos = Vector3(MOD_GRID_COLUMN * MOD_CUBE_SIZE * 0.5f + MOD_CUBE_SIZE * 0.5f, MOD_GRID_LINES * MOD_CUBE_SIZE + MOD_CUBE_SIZE * 0.5f, 0.f);
			for (nCubeIdx = 0; nCubeIdx < 4; nCubeIdx++)
			{
				sprintf(szId, "cube_%d_%d", m_nPieceId, nCubeIdx);
				pEntCube = pScene->createEntity(szId, GetMesh(nCubeIdx));
				sprintf(szId, "NodeCube_%d_%d",m_nPieceId, nCubeIdx);	
				vCubePos = Vector3(0.f, nCubeIdx * MOD_CUBE_SIZE, 0.f);
				pNodeCube = (SceneNode*)m_pParentNode->createChild(szId, vCubePos);
				pNodeCube->attachObject(pEntCube);

				aabb = pEntCube->getBoundingBox();
				vScaleFactor = 1.f - (aabb.getSize() / MOD_CUBE_SIZE - 1.f); 
				pNodeCube->scale(vScaleFactor); 
			}			
			break;
		}
		case PIECE_T:
		{
			m_vParentPos = Vector3(MOD_GRID_COLUMN * MOD_CUBE_SIZE * 0.5f - MOD_CUBE_SIZE * 0.5f, MOD_GRID_LINES * MOD_CUBE_SIZE + MOD_CUBE_SIZE * 0.5f, 0.f);
			for (nCubeIdx = 0; nCubeIdx < 3; nCubeIdx++)
			{
				sprintf(szId, "cube_%d_%d", m_nPieceId, nCubeIdx);
				pEntCube = pScene->createEntity(szId, GetMesh(nCubeIdx));
				sprintf(szId, "NodeCube_%d_%d",m_nPieceId, nCubeIdx);	
				vCubePos = Vector3(nCubeIdx * MOD_CUBE_SIZE, 0.f, 0.f);
				pNodeCube = (SceneNode*)m_pParentNode->createChild(szId, vCubePos);
				pNodeCube->attachObject(pEntCube);

				aabb = pEntCube->getBoundingBox();
				vScaleFactor = 1.f - (aabb.getSize() / MOD_CUBE_SIZE - 1.f); 
				pNodeCube->scale(vScaleFactor); 
			}
			sprintf(szId, "cube_%d_%d", m_nPieceId, ++nCubeIdx);
			pEntCube = pScene->createEntity(szId, GetMesh(nCubeIdx));
			sprintf(szId, "NodeCube_%d_%d",m_nPieceId, nCubeIdx);	
			vCubePos = Vector3(MOD_CUBE_SIZE, -MOD_CUBE_SIZE, 0.f);
			pNodeCube = (SceneNode*)m_pParentNode->createChild(szId, vCubePos);
			pNodeCube->attachObject(pEntCube);

			aabb = pEntCube->getBoundingBox();
			vScaleFactor = 1.f - (aabb.getSize() / MOD_CUBE_SIZE - 1.f); 
			pNodeCube->scale(vScaleFactor); 									
			break;
		}
		case PIECE_SQUARE:
		{
			m_vParentPos = Vector3(MOD_GRID_COLUMN * MOD_CUBE_SIZE * 0.5f - MOD_CUBE_SIZE * 0.5f, MOD_GRID_LINES * MOD_CUBE_SIZE + MOD_CUBE_SIZE * 0.5f, 0.f);
			for (nCubeIdx = 0; nCubeIdx < 4; nCubeIdx++)
			{
				sprintf(szId, "cube_%d_%d", m_nPieceId, nCubeIdx);
				pEntCube = pScene->createEntity(szId, GetMesh(nCubeIdx));
				sprintf(szId, "NodeCube_%d_%d",m_nPieceId, nCubeIdx);	
				if (nCubeIdx < 2)
					vCubePos = Vector3(nCubeIdx * MOD_CUBE_SIZE, 0.f, 0.f);
				else
					vCubePos = Vector3((nCubeIdx - 2 )* MOD_CUBE_SIZE, MOD_CUBE_SIZE, 0.f);
				pNodeCube = (SceneNode*)m_pParentNode->createChild(szId, vCubePos);
				pNodeCube->attachObject(pEntCube);

				aabb = pEntCube->getBoundingBox();
				vScaleFactor = 1.f - (aabb.getSize() / MOD_CUBE_SIZE - 1.f); 
				pNodeCube->scale(vScaleFactor); 
			}
			break;
		}						
		case PIECE_L:
		{
			m_vParentPos = Vector3(MOD_GRID_COLUMN * MOD_CUBE_SIZE * 0.5f + MOD_CUBE_SIZE * 0.5f, MOD_GRID_LINES * MOD_CUBE_SIZE + MOD_CUBE_SIZE * 0.5f, 0.f);
			for (nCubeIdx = 0; nCubeIdx < 3; nCubeIdx++)
			{
				sprintf(szId, "cube_%d_%d", m_nPieceId, nCubeIdx);
				pEntCube = pScene->createEntity(szId, GetMesh(nCubeIdx));
				sprintf(szId, "NodeCube_%d_%d",m_nPieceId, nCubeIdx);	
				vCubePos = Vector3(0.f, nCubeIdx * MOD_CUBE_SIZE, 0.f);
				pNodeCube = (SceneNode*)m_pParentNode->createChild(szId, vCubePos);
				pNodeCube->attachObject(pEntCube);

				aabb = pEntCube->getBoundingBox();
				vScaleFactor = 1.f - (aabb.getSize() / MOD_CUBE_SIZE - 1.f); 
				pNodeCube->scale(vScaleFactor); 
			}
			sprintf(szId, "cube_%d_%d", m_nPieceId, ++nCubeIdx);
			pEntCube = pScene->createEntity(szId, GetMesh(nCubeIdx));
			sprintf(szId, "NodeCube_%d_%d",m_nPieceId, nCubeIdx);	
			vCubePos = Vector3(MOD_CUBE_SIZE, 0, 0.f);
			pNodeCube = (SceneNode*)m_pParentNode->createChild(szId, vCubePos);
			pNodeCube->attachObject(pEntCube);

			aabb = pEntCube->getBoundingBox();
			vScaleFactor = 1.f - (aabb.getSize() / MOD_CUBE_SIZE - 1.f); 
			pNodeCube->scale(vScaleFactor); 
									
			break;
		}		
		case PIECE_N:
		{
			m_vParentPos = Vector3(MOD_GRID_COLUMN * MOD_CUBE_SIZE * 0.5f + MOD_CUBE_SIZE * 0.5f, MOD_GRID_LINES * MOD_CUBE_SIZE + MOD_CUBE_SIZE * 0.5f, 0.f);
			for (nCubeIdx = 0; nCubeIdx < 4; nCubeIdx++)
			{
				sprintf(szId, "cube_%d_%d", m_nPieceId, nCubeIdx);
				pEntCube = pScene->createEntity(szId, GetMesh(nCubeIdx));
				sprintf(szId, "NodeCube_%d_%d", m_nPieceId, nCubeIdx);	
				if (nCubeIdx < 2)
					vCubePos = Vector3(0.f, nCubeIdx * MOD_CUBE_SIZE, 0.f);
				else
					vCubePos = Vector3(-MOD_CUBE_SIZE, (nCubeIdx - 1) * MOD_CUBE_SIZE, 0.f);
				pNodeCube = (SceneNode*)m_pParentNode->createChild(szId, vCubePos);
				pNodeCube->attachObject(pEntCube);

				aabb = pEntCube->getBoundingBox();
				vScaleFactor = 1.f - (aabb.getSize() / MOD_CUBE_SIZE - 1.f); 
				pNodeCube->scale(vScaleFactor); 
			}
			break;
		}
		case PIECE_L_MIRR:
		{
			m_vParentPos = Vector3(MOD_GRID_COLUMN * MOD_CUBE_SIZE * 0.5f + MOD_CUBE_SIZE * 0.5f, MOD_GRID_LINES * MOD_CUBE_SIZE + MOD_CUBE_SIZE * 0.5f, 0.f);
			for (nCubeIdx = 0; nCubeIdx < 3; nCubeIdx++)
			{
				sprintf(szId, "cube_%d_%d", m_nPieceId, nCubeIdx);
				pEntCube = pScene->createEntity(szId, GetMesh(nCubeIdx));
				sprintf(szId, "NodeCube_%d_%d",m_nPieceId, nCubeIdx);	
				vCubePos = Vector3(0.f, nCubeIdx * MOD_CUBE_SIZE, 0.f);
				pNodeCube = (SceneNode*)m_pParentNode->createChild(szId, vCubePos);
				pNodeCube->attachObject(pEntCube);

				aabb = pEntCube->getBoundingBox();
				vScaleFactor = 1.f - (aabb.getSize() / MOD_CUBE_SIZE - 1.f); 
				pNodeCube->scale(vScaleFactor); 
			}
			sprintf(szId, "cube_%d_%d", m_nPieceId, ++nCubeIdx);
			pEntCube = pScene->createEntity(szId, GetMesh(nCubeIdx));
			sprintf(szId, "NodeCube_%d_%d",m_nPieceId, nCubeIdx);	
			vCubePos = Vector3(-MOD_CUBE_SIZE, 0, 0.f);
			pNodeCube = (SceneNode*)m_pParentNode->createChild(szId, vCubePos);
			pNodeCube->attachObject(pEntCube);

			aabb = pEntCube->getBoundingBox();
			vScaleFactor = 1.f - (aabb.getSize() / MOD_CUBE_SIZE - 1.f); 
			pNodeCube->scale(vScaleFactor); 

			break;
		}		
		case PIECE_N_MIRR:
		{
			m_vParentPos = Vector3(MOD_GRID_COLUMN * MOD_CUBE_SIZE * 0.5f + MOD_CUBE_SIZE * 0.5f, MOD_GRID_LINES * MOD_CUBE_SIZE + MOD_CUBE_SIZE * 0.5f, 0.f);
			for (nCubeIdx = 0; nCubeIdx < 4; nCubeIdx++)
			{
				sprintf(szId, "cube_%d_%d", m_nPieceId, nCubeIdx);
				pEntCube = pScene->createEntity(szId, GetMesh(nCubeIdx));
				sprintf(szId, "NodeCube_%d_%d", m_nPieceId, nCubeIdx);	
				if (nCubeIdx < 2)
					vCubePos = Vector3(-MOD_CUBE_SIZE, nCubeIdx * MOD_CUBE_SIZE, 0.f);
				else
					vCubePos = Vector3(0.f, (nCubeIdx - 1) * MOD_CUBE_SIZE, 0.f);
				pNodeCube = (SceneNode*)m_pParentNode->createChild(szId, vCubePos);
				pNodeCube->attachObject(pEntCube);

				aabb = pEntCube->getBoundingBox();
				vScaleFactor = 1.f - (aabb.getSize() / MOD_CUBE_SIZE - 1.f); 
				pNodeCube->scale(vScaleFactor); 
			}
			break;
		}
	}
	m_vInitialPos = m_vParentPos;
	m_pParentNode->setPosition(m_vParentPos);   
#ifdef _DEBUG
	//m_pParentNode->showBoundingBox(true);
#endif //_DEBUG	
}

const Ogre::String	cTetrisPiece::GetMesh(int idx)
{
	switch(idx)
	{
		case 0:
		{
			return "CubeRed.mesh";
			break;
		}
		case 1:
		{
			return "CubeGreen.mesh";
			break;
		}
		case 2:
		{
			return "CubeBlue.mesh";
			break;
		}
		case 3:
		{
			return "CubePurple.mesh";
			break;
		}
	}
	return "CubePurple.mesh";	
}

const Ogre::String cTetrisPiece::GetRandomMesh()
{
	int color = (int)Math::RangeRandom(0.f, 3.9f);
	switch(color)
	{
		case 0:
		{
			return "CubeRed.mesh";
			break;
		}
		case 1:
		{
			return "CubeGreen.mesh";
			break;
		}
		case 2:
		{
			return "CubeBlue.mesh";
			break;
		}
		case 3:
		{
			return "CubePurple.mesh";
			break;
		}
	}
	return "CubePurple.mesh";
}